package com.pig4cloud.pig.common.core.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import com.google.gson.*;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.xml.transform.OutputKeys;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.Locale;
import java.util.TimeZone;

import static cn.hutool.core.date.DatePattern.*;
import static java.time.format.DateTimeFormatter.ofPattern;

@Configuration
public class JsonAutoConfig {

    /**
     * <p>拓展 GsonAutoConfiguration</p>
     * json 时间格式处理
     *
     * @author lw
     */
    @Configuration
    @ConditionalOnClass({Gson.class})
    @AutoConfigureBefore(GsonAutoConfiguration.class)
    public class GsonAutoConfig {

        @Bean
        public Gson gson(GsonBuilder gsonBuilder) {
            return gsonBuilder
                    // LocalDateTime 序列化、反序列化
                    .registerTypeHierarchyAdapter(LocalDateTime.class, (JsonSerializer<LocalDateTime>) (data, type, json) -> new JsonPrimitive(data.format(ofPattern(NORM_DATETIME_MS_PATTERN))))
                    .registerTypeHierarchyAdapter(LocalDateTime.class, (JsonDeserializer<LocalDateTime>) (data, type, json) -> LocalDateTime.parse(data.getAsString(), ofPattern(NORM_DATETIME_MS_PATTERN)))
                    // LocalDate 序列化、反序列化
                    .registerTypeHierarchyAdapter(LocalDate.class, (JsonSerializer<LocalDate>) (data, type, json) -> new JsonPrimitive(data.format(ofPattern(NORM_DATE_PATTERN))))
                    .registerTypeHierarchyAdapter(LocalDate.class, (JsonDeserializer<LocalDate>) (data, type, json) -> LocalDate.parse(data.getAsString(), ofPattern(NORM_DATE_PATTERN)))
                    // LocalTime 序列化、反序列化
                    .registerTypeHierarchyAdapter(LocalTime.class, (JsonSerializer<LocalTime>) (data, type, json) -> new JsonPrimitive(data.format(ofPattern(NORM_TIME_PATTERN))))
                    .registerTypeHierarchyAdapter(LocalTime.class, (JsonDeserializer<LocalTime>) (data, type, json) -> LocalTime.parse(data.getAsString(), ofPattern(NORM_TIME_PATTERN)))
                    .create();
        }


    }

    /**
     * JacksonConfig
     *
     * @author L.cm
     * @author: lengleng
     * @author: lishangbu
     * @date: 2018/10/22
     */
    @Configuration
    @ConditionalOnClass(ObjectMapper.class)
    @AutoConfigureBefore(JacksonAutoConfiguration.class)
    public class JacksonConfig {
        @Bean
        public Jackson2ObjectMapperBuilderCustomizer customizer() {
            return (builder) -> builder.locale(Locale.CHINA).timeZone(TimeZone.getTimeZone(ZoneId.systemDefault())).simpleDateFormat(NORM_DATETIME_PATTERN).modules(new TimeModule());
        }


        /**
         * java 8 时间默认序列化
         *
         * @author L.cm
         * @author lishanbu
         */
        public class TimeModule extends SimpleModule {

            public TimeModule() {
                super(OutputKeys.VERSION);
                this.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(ofPattern(NORM_DATETIME_PATTERN))).addSerializer(LocalDate.class, new LocalDateSerializer(ofPattern(NORM_DATE_PATTERN)))
                        .addSerializer(LocalTime.class, new LocalTimeSerializer(ofPattern(NORM_TIME_PATTERN))).addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(ofPattern(NORM_DATETIME_PATTERN)))
                        .addDeserializer(LocalDate.class, new LocalDateDeserializer(ofPattern(NORM_DATE_PATTERN))).addDeserializer(LocalTime.class, new LocalTimeDeserializer(ofPattern(NORM_TIME_PATTERN)));
            }
        }

    }

}
